package com.mtsoft.mfkernel;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Mark.Taylor
 */
public class Field {
    private Field parent;
    private List<Field> children = new ArrayList<Field>();
    private FieldType fieldType;
    private StorageType storageType;
    private Field redefines; //?
    private String label;
    private int start;
    private int length;
    private int storageLength;
    private int scale;
    private boolean signed; //?
    private int level;  //?
    private String display;
    private String hex;
    private boolean error;
    private String encoding;

    public Field(){}

    public Field(String label, FieldType fieldType, StorageType storageType, int start, int length, int scale, boolean ibmComp) {
        this.label = label;
        this.fieldType = fieldType;
        this.storageType = storageType;
        this.start = start;
        this.length = length;
        this.scale = scale;

        switch(storageType) {
            case PACKED:
                if(length / 2 == 0) {
                    storageLength = (length + 2)/2;
                } else {
                    storageLength = (length + 1)/2;
                }
                break;
            case BINARY:
                storageLength = Util.getBinaryStorageLength(length, ibmComp);
                break;
            default:
                storageLength = length;
        }
    }

    public void addField(Field f) {
        f.setParent(this);
        children.add(f);
    }

    public boolean isGroup() {
        return children.size() > 0;
    }

    public String getLineFromStringList(ArrayList<String> list) {
        if(!isGroup() && !list.isEmpty()) {
            String s = list.remove(0);
            setDisplay(s);
            return ""; //getData();
        } else {
            StringBuilder buffer = new StringBuilder();
            for(Field f : children) {
                String temp = f.getLineFromStringList(list);
                buffer.append(temp);
            }
            return buffer.toString();
        }
    }

    public List<String> getFieldLabelAsList() {
        List<String> list = new ArrayList<String>();
        if(!isGroup()) {
            list.add(label);
        } else {
            for(Field f : children) {
                list.addAll(f.getFieldLabelAsList());
            }
        }
        return list;
    }

    public List<String> getFieldValueAsList() {
        List<String> list = new ArrayList<String>();
        if(!isGroup()) {
            list.add(getDisplay());
        } else {
            for(Field f : children) {
                list.addAll(f.getFieldValueAsList());
            }
        }
        return list;
    }

    public List<Field> getFieldsAsList() {
        List<Field> list = new ArrayList<Field>();
        list.add(this);
        for(Field f : children) {
            list.addAll(f.getFieldsAsList());
        }
        return list;
    }

    public String getdefaultDisplay() {
        String retVal = "";
        if(!isGroup()) {
            switch(fieldType) {
                case NUMERIC:
                    retVal = "0";
                    break;
                case DECIMAL:
                    retVal = "0.0";
                    break;
                case STRING:
                    retVal = " ";
                    break;
            }
        }
        return retVal;
    }

//    public void getAsLine(StringBuilder buffer) {
//        int begin = Math.min(start, buffer.length());
//        int end   = Math.min(begin + length, buffer.length());
//        if(children.size() == 0) {
//            //TODO parse data from diplay:
//            data = display;
//            //buffer.replace(begin, end, data);
//            FieldFormatter.setStringInBuffer(buffer, display, start, length);
//        } else {
//            for(Field f : children) {
//                if(!redefines)
//                    f.getAsLine(buffer);
//            }
//        }
//    }

    public Field getParent() {
        return parent;
    }

    public void setParent(Field parent) {
        this.parent = parent;
    }

    public List<Field> getChildren() {
        return children;
    }

    public void setChildren(List<Field> children) {
        this.children = children;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
        if(storageType == StorageType.PACKED) {
            if(length / 2 == 0) {
                storageLength = (length + 2)/2;
            } else {
                storageLength = (length + 1)/2;
            }
        } else {
            storageLength = length;
        }
    }

    public int getStorageLength() {
        return storageLength;
    }

    public void setStorageLength(int storageLength) {
        this.storageLength = storageLength;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getScale() {
        return scale;
    }

    public void setScale(int scale) {
        this.scale = scale;
    }

    public boolean isSigned() {
        return signed;
    }

    public void setSigned(boolean signed) {
        this.signed = signed;
    }

    public FieldType getFieldType() {
        return fieldType;
    }

    public void setFieldType(FieldType type) {
        this.fieldType = type;
    }

    public StorageType getStorageType() {
        return storageType;
    }

    public void setStorageType(StorageType storageType) {
        this.storageType = storageType;
    }

    public Field getRedefines() {
        return redefines;
    }

    public void setRedefines(Field redefines) {
        this.redefines = redefines;
    }

    public String getDisplay() {
        return display;
    }

    public void setDisplay(String display) {
        this.display = display;
    }

    public String getHex() {
        return hex;
    }

    public void setHex(String hex) {
        this.hex = hex;
    }
    
    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public boolean isError() {
        return error;
    }

    public boolean getError() {
        return error;
    }
    public void setError(boolean error) {
        this.error = error;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    @Override
    public String toString() {
        return  ""+level+" "+label+" " + " ("+start+","+length+")" + " type="+fieldType.name()
                + (redefines != null ? " redefine="+redefines.label : "");
    }

    public void printTree(String indent) {
        System.out.println(indent + toString());
        for(Field f : children) {
            f.printTree(indent+"  ");
        }
    }

    public String getDataTypeDisplay() {
        if(storageType == null || fieldType == null) {
            return "";
        }
        StringBuilder buffer = new StringBuilder();
        switch(storageType){
            case ALPHA:
                buffer.append("A");
                break;
            case BINARY:
                buffer.append("B");
                break;
            case PACKED:
                buffer.append("P");
                break;
            case UNSIGNED:
            case ZONED:
                buffer.append("N");
                break;
        }
        switch(fieldType) {
            case DECIMAL:
                buffer.append("("+length+","+scale+")");
                break;
            case NUMERIC:
                buffer.append("("+length+")");
                break;
            case STRING:
                buffer.append("("+length+")");
                break;
        }
        return buffer.toString();
    }
}
